﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Dominio;
using Lucene.Net.Store;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Directory = Lucene.Net.Store.Directory;
using Version = Lucene.Net.Util.Version;

namespace Servicios
{
    public class IndexServiceLuceneImpl : IIndexService
    {
        private static readonly string LUCENE_LOCATION = "//"+System.Net.Dns.GetHostName()+"/SearchServer/LuceneIndex";

        private ILogService logService = FabricaDeServicios.ObtenerInstancia().ObtenerLogService();

        private IFileSystemElementService fileSystemElementService = FabricaDeServicios.ObtenerInstancia().ObtenerFileSystemElementService();

        private static IndexServiceLuceneImpl instancia = new IndexServiceLuceneImpl();

        private IndexServiceLuceneImpl() : base() { }

        public static IndexServiceLuceneImpl ObtenerInstancia()
        {
            return instancia;
        }

        public void AgregarIndice(FileSystemElement fse)
        {
            Directory directory = FSDirectory.Open(new DirectoryInfo(LUCENE_LOCATION));
            IndexWriter writer = new IndexWriter(directory,
                new StandardAnalyzer(Version.LUCENE_29), true,
                IndexWriter.MaxFieldLength.UNLIMITED);

            Document doc = new Document();
            doc.Add(new Field("id", fse.Id.ToString(), Field.Store.YES, Field.Index.NO));
            doc.Add(new Field("nombre", fse.Nombre, Field.Store.YES, Field.Index.ANALYZED));
            doc.Add(new Field("ruta", fse.Ruta, Field.Store.YES, Field.Index.ANALYZED));
            doc.Add(new Field("extension", fse.GetExtension(), Field.Store.YES, Field.Index.ANALYZED));
            doc.Add(new Field("fecha", fse.Fecha.ToShortDateString(), Field.Store.YES, Field.Index.ANALYZED));
            writer.AddDocument(doc);

            writer.Optimize();
            writer.Close();
            directory.Close();
        }

        public void ModificarIndice(FileSystemElement fse)
        {
            BorrarIndice(fse);
            AgregarIndice(fse);
            
        }

        public void BorrarIndice(FileSystemElement fse)
        {
            IndexModifier modifier = new IndexModifier(LUCENE_LOCATION, new StandardAnalyzer(Version.LUCENE_29), true);
            
            modifier.DeleteDocuments(new Term("id", Convert.ToString(fse.Id)));
        }

        public IList<FileSystemElement> Buscar(string keyword)
        {
            keyword += "*";//Agregamos el comodin

            Directory directory = FSDirectory.Open(new DirectoryInfo(LUCENE_LOCATION));
            //Setup searcher
            IndexReader indexReader = IndexReader.Open(directory, true);
            IndexSearcher searcher = new IndexSearcher(indexReader);
            //Do the search

            //Definir un tope
            int hitsPerPage = 100;

            var query = MultiFieldQueryParser.Parse(Version.LUCENE_29, keyword,
                new[] { "nombre", "extension", "ruta" ,"fecha"},
                new[] { BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD,
                BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD },
                new StandardAnalyzer(Version.LUCENE_29));


            TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage, true);

            searcher.Search(query, collector);


            var hits = collector.TopDocs().ScoreDocs;

            List<FileSystemElement> retorno = new List<FileSystemElement>();
            foreach (var hit in hits)
            {
                Document doc = searcher.Doc(hit.doc);

                FileSystemElement element = fileSystemElementService.ObtenerPorId(Int16.Parse(doc.Get("id")));
                retorno.Add(element);
            }
            indexReader.Close();
            directory.Close();
            return retorno;
        }

        public void BorrarTodo()
        {
            DirectoryInfo dir = new DirectoryInfo(LUCENE_LOCATION);
            FileInfo[] files = dir.GetFiles();
            foreach( FileInfo file in files)
                System.IO.File.Delete(LUCENE_LOCATION + "\\" + file.Name);
        }
    }
}
